﻿using DocumentFormat.OpenXml.Lite.Core.ContentType;
using DocumentFormat.OpenXml.Lite.Core.Interfaces;
using DocumentFormat.OpenXml.Lite.Core.Relationship;
using DocumentFormat.OpenXml.Lite.Shared;
using DFS = DocumentFormat.OpenXml.Lite.Core.DocumentFS;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;

namespace DocumentFormat.OpenXml.Lite.Core.Office
{
    public abstract class DocumentBase
    {
        public Guid Id { get; private set; }
        public DocumentType Type { get; private set; }
        public ContentTypeManager ContentTypeManager { get; protected set; }
        public List<RelationshipManager> RelationshipManagers { get; protected set; }

        private AppProperties appProperties;
        public AppProperties AppProperties 
        {
            get { return appProperties; }
            set
            {
                appProperties = value;
                DFS.Directory sandbox = DFS.DocumentFS.GetSandbox(Id);
                if (!sandbox.ExistsDirectory("docProps"))
                {
                    sandbox.CreateDirectory("docProps");
                }

                if (!sandbox.GetDirectory("docProps").ExistsFile("app.xml"))
                {
                    var file = sandbox.GetDirectory("docProps").CreateFile("app.xml", value);

                    var relManager = sandbox.GetDirectory("_rels").GetFile(".rels").Object as RelationshipManager;
                    relManager.CreateRelationship(RelationshipURI.ExtentendedProperties, file);

                    ContentTypeManager.CreateOverride(ContentType.ContentType.App, file);
                }
                else
                {
                    sandbox.GetDirectory("docProps").GetFile("app.xml").Object = value;
                }
            }
        }

        private CoreProperties coreProperties;
        public CoreProperties CoreProperties
        {
            get { return coreProperties; }
            set
            {
                coreProperties = value;
                DFS.Directory sandbox = DFS.DocumentFS.GetSandbox(Id);
                if (!sandbox.ExistsDirectory("docProps"))
                {
                    sandbox.CreateDirectory("docProps");
                }

                if (!sandbox.GetDirectory("docProps").ExistsFile("core.xml"))
                {
                    DFS.File file = sandbox.GetDirectory("docProps").CreateFile("core.xml", value);

                    var relManager = sandbox.GetDirectory("_rels").GetFile(".rels").Object as RelationshipManager;
                    relManager.CreateRelationship(RelationshipURI.CoreProperties, file);

                    ContentTypeManager.CreateOverride(ContentType.ContentType.Core, file);
                }
                else
                {
                    sandbox.GetDirectory("docProps").GetFile("core.xml").Object = value;
                }
            }
        }

        public DocumentBase(Guid id, DocumentType type)
        {
            this.Id = id;
            RelationshipManagers = new List<RelationshipManager>();
        }

        public virtual string AddEmbeddingFor(ISerializable obj, Embedding em, RelationshipURI relUri, Default def)
        {
            return string.Empty;
        }

        public virtual T FindElementFor<T>(object obj, string relationshipId)
        {
            DFS.Directory sandbox = DFS.DocumentFS.GetSandbox(Id);
            DFS.File file = sandbox.GetFilesRecursive().FirstOrDefault(f => f.Object == obj);
            if (file == null)
            {
                throw new NullReferenceException("Cannot find object!");
            }
            file = sandbox.GetFilesRecursive().FirstOrDefault(f => f.Name == file.Name + ".rels");
            if (file == null)
            {
                throw new NullReferenceException("Cannot find object!");
            }
            var target = (file.Object as RelationshipManager).RelationshipTags
                .FirstOrDefault(r => r.Id == relationshipId).Target;
            if (target == null || target == string.Empty)
            {
                throw new NullReferenceException("Cannot find object!");
            }
            var o = sandbox.GetFile(DFS.Directory.Combine(file.Parent.Parent, target)).Object;
            if (!(o is T))
            {
                throw new ArgumentException("Invalid object type: " + typeof(T).ToString() + ".");
            }
            return (T)o;
        }

        public abstract void CreateDefault();

        public virtual bool ExtractFile(string file, System.IO.Stream content)
        {
            if (file == @"docProps\app.xml" || file == @"docProps/app.xml")
            {
                AppProperties = new AppProperties();
                AppProperties.Deserialize(content);
                return true;
            }
            else if (file == @"docProps\core.xml" || file == @"docProps/core.xml")
            {
                CoreProperties = new CoreProperties();
                CoreProperties.Deserialize(content);
                return true;
            }

            return false;
        }
    }
}
